home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / enscript.4 / enscript / enscript-1.4.0 / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-16  |  41.7 KB  |  1,690 lines

  1. /* 
  2.  * Argument handling and main.
  3.  * Copyright (c) 1995 Markku Rossi.
  4.  *
  5.  * Author: Markku Rossi <mtr@iki.fi> 
  6.  */
  7.  
  8. /*
  9.  * This file is part of GNU enscript.
  10.  * 
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2, or (at your option)
  14.  * any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 59 Temple Place - Suite 330,
  24.  * Boston, MA 02111-1307, USA.
  25.  */
  26.  
  27. #include "gsint.h"
  28. #include "getopt.h"
  29.  
  30. /*
  31.  * Prototypes for static functions.
  32.  */
  33.  
  34. /* Handle options from environment variable <var> */
  35. static void handle_env_options __P ((char *var));
  36.  
  37. /* Handle options from <argv> array. */
  38. static void handle_options __P ((int argc, char *argv[]));
  39.  
  40. /* List options and their values. */
  41. static void do_list_options ();
  42.  
  43. /* Print usage info. */
  44. static void usage ();
  45.  
  46. /* Print version info. */
  47. static void version ();
  48.  
  49.  
  50. /*
  51.  * Global variables.
  52.  */
  53.  
  54. char *program;            /* Program's name, used for messages. */
  55. FILE *ofp;            /* Output file. */
  56. char version_string[256];    /* Enscript's version string. */
  57. char ps_version_string[20];    /* Version string for PS procsets. */
  58. char date_string[256];        /* Preformatted time string. */
  59. struct tm run_tm;        /* Time when program is run. */
  60. struct tm mod_tm;        /* Last modification time for current file. */
  61. struct passwd *passwd;        /* Passwd entry for the user running this 
  62.                    program. */
  63.  
  64. /* Path to our library. */
  65. char *enscript_library = LIBRARY;
  66.  
  67. /* Library lookup path. */
  68. char libpath[1024];
  69.  
  70. /* AFM library lookup path. */
  71. char *afm_path = NULL;
  72. char afm_path_buffer[1024];
  73.  
  74. MediaEntry *media_names = NULL;    /* List of known media. */
  75. MediaEntry *media = NULL;    /* Entry for used media. */
  76. char spooler_command[256];    /* Name of the spooler command. */
  77. char queue_param[16];        /* Parameter for print queue (-P). */
  78. char spooler_options[512];    /* Array of spooler options. */
  79. int bs = 8;            /* The backspace character. */
  80.  
  81. /* Statistics. */
  82. int total_pages = 0;        /* Total number of pages printed. */
  83. int num_truncated_lines = 0;    /* Number of lines truncated. */
  84. int num_missing_chars = 0;    /* Number of unknown characters. */
  85. int missing_chars[256] = {0};    /* Table of unknown characters. */
  86. int num_non_printable_chars = 0; /* Number of non-printable characters. */
  87. int non_printable_chars[256] = {0}; /* Table of non-printable characters. */
  88.  
  89. /* Output media dimensions that are used during PostScript emission. */
  90. int d_page_w = 0;        /* page's width */
  91. int d_page_h = 0;        /* page's height */
  92. int d_header_w = 0;        /* fancy header's width */
  93. int d_header_h = 0;        /* fancy header's height */
  94. int d_footer_h = 0;        /* fancy footer's height */
  95. int d_output_w = 0;        /* output area's width */
  96. int d_output_h = 0;        /* output area's height  */
  97. int d_output_x_margin = 5;    /* output area's x marginal */
  98. int d_output_y_margin = 2;    /* output area's y marginal */
  99.  
  100. /* Document needed resources. */
  101. StringHashPtr res_fonts;    /* fonts */
  102.  
  103. /* Fonts to download. */
  104. StringHashPtr download_fonts;
  105.  
  106. /* Additional key-value pairs, passed to the generated PostScript code. */
  107. StringHashPtr pagedevice;    /* for setpagedevice */
  108. StringHashPtr statusdict;    /* for statusdict */
  109.  
  110. /* User defined strings. */
  111. StringHashPtr user_strings;
  112.  
  113. /* Cache for AFM files. */
  114. StringHashPtr afm_cache = NULL;
  115.  
  116. /* AFM library handle. */
  117. AFMHandle afm = NULL;
  118.  
  119.  
  120. /* Options. */
  121.  
  122. /* 
  123.  * -1, -2, --columns
  124.  *
  125.  * Number of columns per page.  Default is 1 column.
  126.  */
  127. int num_columns = 1;
  128.  
  129. /*
  130.  * -a PAGES, --pages=PAGES
  131.  *
  132.  * Specify which pages are printed.
  133.  */
  134. PageRange *page_ranges = NULL;
  135.  
  136. /* 
  137.  * -b, --header
  138.  * 
  139.  * Set string to be used as a page header.  As a default page header is 
  140.  * constructed from filename, date and page number.
  141.  */
  142. char *page_header = NULL;
  143.  
  144. /* 
  145.  * -B, --no-header
  146.  *
  147.  * Do not print page headers.
  148.  */
  149.  
  150. /*
  151.  * -c, --truncate-lines
  152.  *
  153.  * Truncate lines that are longer than the page width.  Default is wrap.
  154.  */
  155. int truncate_lines = 0;
  156.  
  157. /*
  158.  * -C, --line-numbers
  159.  *
  160.  * Precede each line with its line number.  As a default, do not mark
  161.  * line numbers.
  162.  */
  163. int line_numbers = 0;
  164.  
  165. /*
  166.  * -d, -P, --printer
  167.  *
  168.  * Name of the printer to which output is send.  Defaults to system's
  169.  * default printer.
  170.  */
  171. char *printer = NULL;
  172. char printer_buf[256];
  173.  
  174. /* 
  175.  * -e [CHAR], --escapes[=CHAR]
  176.  *
  177.  * Enable special escape ('\000') interpretation.  If option CHAR is given
  178.  * it is assumed to specify the escape character.
  179.  */
  180. int special_escapes = 0;
  181. int escape_char = '\0';
  182.  
  183. /*
  184.  * -f, --font
  185.  *
  186.  * Select body font.
  187.  */
  188. char *Fname = "Courier";
  189. double Fpt = 10.0;
  190. double default_Fpt;        /* Point size of the original font. */
  191. char *default_Fname;        /* Name of the original font. */
  192. int user_body_font_defined = 0;    /* Has user defined new body font? */
  193.  
  194. double font_widths[256];    /* Width array for body font. */
  195. char font_ctype[256];        /* Font character types. */
  196. int font_is_fixed;        /* Is body font a fixed pitch font? */
  197. double font_bbox_lly;        /* Font's bounding box's lly-coordinate. */
  198.  
  199. /*
  200.  * -F, --header-font
  201.  *
  202.  * Select font to be used to print the standard simple header.
  203.  */
  204. char *HFname = "Courier-Bold";
  205. double HFpt = 10.0;
  206.  
  207. /*
  208.  * -g, --print-anyway
  209.  *
  210.  * Print document even it contains binary data.  This does nothing
  211.  * since enscript prints files anyway.
  212.  */
  213.  
  214. /* 
  215.  * -G, --fancy-header
  216.  *
  217.  * Add a fancy header to top of every page.  There are several header styles
  218.  * but the default is 'no fancy header'.
  219.  */
  220. HeaderType header = HDR_SIMPLE;
  221. char *fancy_header_name = NULL;
  222. char fancy_header_default[256];
  223.  
  224. /*
  225.  * -h, --no-job-header
  226.  *
  227.  * Supress the job header page.
  228.  */
  229. static int no_job_header = 0;
  230.  
  231. /*
  232.  * -H num, --highlight-bars=num
  233.  *
  234.  * Print highlight bars under text.  Bars will be <num> lines high.
  235.  * As a default, do not print bars.
  236.  */
  237. unsigned int highlight_bars = 0;
  238.  
  239. /* 
  240.  * -i, --indent
  241.  *
  242.  * Indent every line this many characters.
  243.  */
  244. double line_indent = 0.0;
  245. char *line_indent_spec = "0";
  246.  
  247. /*
  248.  * -I CMD, --filter=CMD
  249.  *
  250.  * Read input files through input filter CMD.
  251.  */
  252. char *input_filter = NULL;
  253.  
  254. /*
  255.  * -j, --borders
  256.  *
  257.  * Print borders around columns.
  258.  */
  259. int borders = 0;
  260.  
  261. /*
  262.  * -k, --page-prefeed
  263.  * -K, --no-page-prefeed
  264.  *
  265.  * Control page prefeed.
  266.  */
  267. int page_prefeed = 0;
  268.  
  269. /* 
  270.  * -L, --lines-per-page
  271.  *
  272.  * Specify how many lines should be printed on a single page.  Normally
  273.  * enscript counts it from font point sizes.
  274.  */
  275. unsigned int lines_per_page = (unsigned int) -1;
  276.  
  277. /*
  278.  * -m, --mail
  279.  *
  280.  * Send mail notification to user after print job has been completed.
  281.  */
  282. int mail = 0;
  283.  
  284. /* 
  285.  * -M, --media
  286.  *
  287.  * Name of the output media.  Default is A4.
  288.  */
  289. char *media_name = "A4";
  290. char media_name_buffer[256];
  291.  
  292. /*
  293.  * -n, --copies
  294.  *
  295.  * Number of copies to print.
  296.  */
  297. int num_copies = 1;
  298.  
  299. /*
  300.  * -N, --newline
  301.  *
  302.  * Set the newline character: '\n' or '\r'.  As a default, the newline
  303.  * character is specified by the input encoding.
  304.  */
  305. int nl = -1;
  306.  
  307. /* 
  308.  * -o, -p, --output
  309.  *
  310.  * Leave output to the specified file.  As a default result is spooled to 
  311.  * printer.
  312.  */
  313. char *output_file = OUTPUT_FILE_NONE;
  314.  
  315. /*
  316.  * -O, --missing-characters
  317.  * 
  318.  * List all missing characters.  Default is no listing.
  319.  */
  320. int list_missing_characters = 0;
  321.  
  322. /* 
  323.  * -q, --quiet
  324.  *
  325.  * Do not tell what we are doing.  Default is to tell something but
  326.  * not --verbose.
  327.  */
  328. int quiet = 0;
  329.  
  330. /*
  331.  * -r, --landscape
  332.  * -R, --portrait
  333.  *
  334.  * Print with page rotated 90 degrees (landscape mode).  Default is
  335.  * portrait.
  336.  */
  337. int landscape = 0;
  338.  
  339. /* 
  340.  * -s, --baselineskip
  341.  *
  342.  * Specify baselineskip value that is used when enscript moves to
  343.  * a new line.  Current point movement is font_point_size + baselineskip.
  344.  */
  345. double baselineskip = 1.0;
  346.  
  347. /* 
  348.  * -t, --title
  349.  * 
  350.  * Title which is printed to the banner page.  If this option is given
  351.  * from the command line, this sets also the name of the stdin which
  352.  * is by the default "".
  353.  */
  354. char *title = "enscript output";
  355. int title_given = 0;
  356.  
  357. /*
  358.  * -T, --tabsize
  359.  *
  360.  * Specify tabulator size.
  361.  */
  362. int tabsize = 8;
  363.  
  364. /* 
  365.  * -u, --underlay
  366.  *
  367.  * Place text under every page.  Default is no underlay.
  368.  */
  369. double ul_gray = .8;
  370. double ul_ptsize = 200.0;
  371. char *ul_font = "Times-Roman";
  372. char *underlay = NULL;
  373. char ul_position_buf[256];
  374. char *ul_position = "+0-0";    /* Position info as a string. */
  375. double ul_x;            /* Position x-coordinate. */
  376. double ul_y;            /* Position y-coordinate. */
  377. double ul_angle;
  378. unsigned int ul_style = UL_STYLE_OUTLINE;
  379. char *ul_style_str = "outline";
  380. char ul_style_str_buf[256];
  381. int ul_position_p = 0;        /* Is ul-position given? */
  382. int ul_angle_p = 0;        /* Is ul-angle given? */
  383.  
  384. /*
  385.  * -v, --verbose
  386.  *
  387.  * Tell what we are doing.  Default is no verbose outputs.
  388.  */
  389. int verbose = 0;
  390.  
  391. /*
  392.  * -X, --encoding
  393.  *
  394.  * Specifies input encoding.  Default is ISO-8859.1.
  395.  */
  396. InputEncoding encoding = ENC_LATIN1;
  397. char *encoding_name = "latin1";
  398. char encoding_name_buffer[256];
  399.  
  400. /*
  401.  * -z, --no-formfeed
  402.  *
  403.  * Do not interpret form feed characters.  As a default, form feed
  404.  * characters are interpreted.
  405.  */
  406. int interpret_formfeed = 1;
  407.  
  408. /* 
  409.  * -Z, --pass-through
  410.  * 
  411.  * Pass through all PostScript and PCL files without any modifications.  
  412.  * As a default, don't.
  413.  */
  414. int pass_through = 0;
  415.  
  416. /*
  417.  * --filter-stdin=STR
  418.  *
  419.  * How stdin is shown to the filter command.  The default is "" but
  420.  * some utilities might want it as "-".
  421.  */
  422. char *input_filter_stdin = "";
  423.  
  424. /*
  425.  * --highlight-bar-gray=val
  426.  *
  427.  * Specify the gray level for highlight bars.
  428.  */
  429. double highlight_bar_gray = .97;
  430.  
  431. /* 
  432.  * --list-media
  433.  *
  434.  * List all known media.  As a default do not list media names.
  435.  */
  436. int list_media = 0;
  437.  
  438. /*
  439.  * --list-options
  440.  *
  441.  * Show all options and their values.  Exit successfully.
  442.  */
  443. int list_options = 0;
  444.  
  445. /*
  446.  * --non-printable-format
  447.  *
  448.  * Format in which non-printable characters are printed.
  449.  */
  450. char *npf_name = "octal";
  451. char npf_name_buf[256];
  452. NonPrintableFormat non_printable_format = NPF_OCTAL;
  453.  
  454. /* 
  455.  * --page-label-format
  456.  *
  457.  * Format in which page labels are printed, default is "short".
  458.  */
  459. char *page_label_format = "short";
  460. char page_label_format_buf[256];
  461. PageLabelFormat page_label;
  462.  
  463. /*
  464.  * --printer-options=OPTIONS
  465.  *
  466.  * Pass extra options OPTIONS to the printer spooler.
  467.  */
  468. char *printer_options = NULL;
  469.  
  470. /*
  471.  * AppendCtrlD: bool
  472.  *
  473.  * Append ^D character to the end of the output.  Some printers require this
  474.  * but the default is false.
  475.  */
  476. int append_ctrl_D = 0;
  477.  
  478. /*
  479.  * Clean7Bit: bool
  480.  *
  481.  * Specify how characters greater than 127 are printed.
  482.  */
  483. int clean_7bit = 1;
  484.  
  485. /* ^@shade{GRAY}, set the line highlight gray. */
  486. double line_highlight_gray = 1.0;
  487.  
  488. /*
  489.  * AcceptCompositeCharacters, specify whatever we accept composite
  490.  * characters or should them be considered as non-existent.  As a
  491.  * default, do not accept them.
  492.  */
  493. int accept_composites = 0;
  494.  
  495. /*
  496.  * FormFeedType, specify what to do when a formfeed character is 
  497.  * encountered from the input stream.  The default action is to jump to
  498.  * the beginning of the next column.
  499.  */
  500. FormFeedType formfeed_type = FORMFEED_COLUMN;
  501.  
  502. /*
  503.  * Static variables.
  504.  */
  505.  
  506. static struct option long_options[] =
  507. {
  508.   {"columns",        required_argument,    0, 0},
  509.   {"pages",        required_argument,    0, 'a'},
  510.   {"header",        required_argument,    0, 'b'},
  511.   {"no-header",        no_argument,        0, 'B'},
  512.   {"truncate-lines",    no_argument,        0, 'c'},
  513.   {"line-numbers",    no_argument,        0, 'C'},
  514.   {"printer",        required_argument,    0, 'd'}, 
  515.   {"setpagedevice",    required_argument,    0, 'D'},
  516.   {"escapes",        optional_argument,    0, 'e'},
  517.   {"font",        required_argument,    0, 'f'},
  518.   {"header-font",    required_argument,    0, 'F'},
  519.   {"print-anyway",    no_argument,        0, 'g'},
  520.   {"fancy-header",    optional_argument,    0, 'G'},
  521.   {"no-job-header",    no_argument,         0, 'h'},
  522.   {"highlight-bars",    optional_argument,    0, 'H'},
  523.   {"indent",        required_argument,    0, 'i'},
  524.   {"filter",        required_argument,    0, 'I'},
  525.   {"borders",        no_argument,        0, 'j'},
  526.   {"page-prefeed",    no_argument,        0, 'k'},
  527.   {"no-page-prefeed",    no_argument,        0, 'K'},
  528.   {"lineprinter",    no_argument,        0, 'l'},
  529.   {"lines-per-page",    required_argument,    0, 'L'},
  530.   {"mail",        no_argument,        0, 'm'},
  531.   {"media",        required_argument,    0, 'M'},
  532.   {"copies",        required_argument,    0, 'n'},
  533.   {"newline",        required_argument,    0, 'N'},
  534.   {"output",        required_argument,    0, 'p'},
  535.   {"missing-characters",    no_argument,    0, 'O'},
  536.   {"quiet",        no_argument,        0, 'q'},
  537.   {"silent",        no_argument,        0, 'q'},
  538.   {"landscape",        no_argument,        0, 'r'},
  539.   {"portrait",        no_argument,        0, 'R'},
  540.   {"baselineskip",    required_argument,    0, 's'},
  541.   {"statusdict",    required_argument,    0, 'S'},
  542.   {"title",        required_argument,    0, 't'},
  543.   {"tabsize",        required_argument,    0, 'T'},
  544.   {"underlay",        optional_argument,    0, 'u'},
  545.   {"verbose",        optional_argument,    0, 'v'},
  546.   {"version",        no_argument,        0, 'V'},
  547.   {"encoding",        required_argument,    0, 'X'},
  548.   {"no-formfeed",    no_argument,        0, 'z'},
  549.   {"pass-through",    no_argument,        0, 'Z'},
  550.  
  551.   /* Long options without short counterparts. */
  552.   {"download-font",    required_argument,    0, 131},
  553.   {"filter-stdin",    required_argument,    0, 138},
  554.   {"help",         no_argument,         0, 135},
  555.   {"highlight-bar-gray",    required_argument,     0, 136},
  556.   {"list-media",    no_argument,        &list_media, 1},
  557.   {"list-options",    no_argument,        &list_options, 1},
  558.   {"non-printable-format",
  559.                  required_argument,    0, 134},
  560.   {"page-label-format",    required_argument,    0, 130},
  561.   {"printer-options",    required_argument,    0, 139},
  562.   {"ul-angle",        required_argument,    0, 132},
  563.   {"ul-font",        required_argument,    0, 128},
  564.   {"ul-gray",        required_argument,    0, 129},
  565.   {"ul-position",    required_argument,    0, 133},
  566.   {"ul-style",        required_argument,    0, 137},
  567.  
  568.   {NULL, 0, 0, 0},
  569. };
  570.  
  571.  
  572. static struct
  573. {
  574.   char *names[3];
  575.   InputEncoding encoding;
  576.   int nl;
  577.   int bs;
  578. } encodings[] =
  579.   {
  580.     {{"latin1", "iso8859", "iso"},    ENC_LATIN1,         '\n', 8},
  581.     {{"latin2", "iso2", NULL},        ENC_LATIN2,         '\n', 8},
  582.     {{"latin3", "iso3", NULL},        ENC_LATIN3,         '\n', 8},
  583.     {{"ascii", NULL, NULL},        ENC_ASCII,         '\n', 8},
  584.     {{"asciiscands", NULL, NULL},    ENC_ASCII_SCANDS,     '\n', 8},
  585.     {{"ibmpc", "pc", "dos"},        ENC_IBMPC,         '\n', 8},
  586.     {{"mac", NULL, NULL},        ENC_MAC,         '\r', 8},
  587.     {{"vms", NULL, NULL},        ENC_VMS,         '\n', 8},
  588.     {{"hp8", NULL, NULL},        ENC_HP8,        '\n', 8},
  589.     {{"ps", "PS", NULL},        ENC_PS,         '\n', 8},
  590.     {{"pslatin1", "ISOLatin1Encoding", NULL},    ENC_LATIN1,    '\n', 8},
  591.  
  592.     {{NULL, NULL, NULL}, 0, 0, 0},
  593.   };
  594.  
  595.  
  596. /* 
  597.  * Global functions.
  598.  */
  599.  
  600. int 
  601. main (int argc, char *argv[])
  602. {
  603.   InputStream is;
  604.   time_t tim;
  605.   struct tm *tm;
  606.   int i, j, found;
  607.   MediaEntry *mentry;
  608.   AFMError afm_error;
  609.   char *cp, *cp2;
  610.   void *printer_context;
  611.  
  612.   /* Get program's name. */
  613.   program = strrchr (argv[0], '/');
  614.   if (program == NULL)
  615.     program = argv[0];
  616.   else
  617.     program++;
  618.  
  619.   /* Make getopt_long() to use our modified programname. */
  620.   argv[0] = program;
  621.  
  622.   /* Create version strings. */
  623.   sprintf (version_string, "GNU %s %s", PACKAGE, VERSION);
  624.   strcpy (ps_version_string, VERSION);
  625.   cp = strrchr (ps_version_string, '.');
  626.   *cp = ' ';
  627.  
  628.   /* Internationalization. */
  629. #if HAVE_SETLOCALE 
  630.   /*
  631.    * We want to change only messages (gs do not like decimals in 0,1
  632.    * format ;)
  633.    */
  634. #if HAVE_LC_MESSAGES
  635.   setlocale (LC_MESSAGES, "");
  636. #endif
  637. #endif
  638. #if ENABLE_NLS
  639.   bindtextdomain (PACKAGE, LOCALEDIR);
  640.   textdomain (PACKAGE);
  641. #endif
  642.  
  643.   /* Create date string. */
  644.  
  645.   tim = time (NULL);
  646.   tm = localtime (&tim);
  647.   memcpy (&run_tm, tm, sizeof (*tm));
  648.  
  649.   sprintf (date_string, "%s", asctime (&run_tm));
  650.   i = strlen (date_string);
  651.   date_string[i - 1] = '\0';
  652.  
  653.   /* Get user's passwd entry. */
  654.   passwd = getpwuid (getuid ());
  655.   if (passwd == NULL)
  656.     fatal (_("couldn't get passwd entry for uid=%d: %s"), getuid (), 
  657.        strerror (errno));
  658.  
  659.   /* Default spooler command name. */
  660.   strcpy (spooler_command, "lpr");
  661.   strcpy (queue_param, "-P");
  662.  
  663.   /* Default fancy header name. */
  664.   strcpy (fancy_header_default, "enscript");
  665.  
  666.   /* Check ENSCRIPT_LIBRARY for custom library location. */
  667.   cp = getenv ("ENSCRIPT_LIBRARY");
  668.   if (cp)
  669.     enscript_library = cp;
  670.     
  671.   /* Fill up build-in libpath. */
  672.   sprintf (libpath, "%s%c%s/.enscript", enscript_library, PATH_SEPARATOR,
  673.        passwd->pw_dir);
  674.  
  675.   /* Initialize resource sets. */
  676.   res_fonts = strhash_init ();
  677.   download_fonts = strhash_init ();
  678.   pagedevice = strhash_init ();
  679.   statusdict = strhash_init ();
  680.   user_strings = strhash_init ();
  681.  
  682.  
  683.   /* 
  684.    * Read configuration files. 
  685.    */
  686.  
  687.   /* Global config. */
  688. #define CFG_FILE_NAME "enscript.cfg"
  689.   if (!read_config (SYSCONFDIR, CFG_FILE_NAME))
  690.     {
  691.       int saved_errno = errno;
  692.  
  693.       /*
  694.        * Try to read it from our library directory.  This is mostly the
  695.        * case for the micro ports.
  696.        */
  697.       if (!read_config (enscript_library, CFG_FILE_NAME))
  698.     {
  699.       /* Maybe we are not installed yet, let's try "../lib". */
  700.       if (!read_config ("../lib", CFG_FILE_NAME))
  701.         {
  702.           /* No luck, report error from the original config file. */
  703.           fatal (_("couldn't open config file \"%s/%s\": %s"),
  704.              enscript_library, CFG_FILE_NAME, strerror (saved_errno));
  705.         }
  706.  
  707.       /*
  708.        * Ok, we are not installed yet.  Here is a small kludge to
  709.        * conform the GNU coding standards: we must be able to run
  710.        * without being installed, so we must append the "../lib"
  711.        * directory to the libpath.
  712.        */
  713.       strcat (libpath, ":../lib");
  714.     }
  715.     }
  716.  
  717.   /* Site config. */
  718.   (void) read_config (SYSCONFDIR, "enscriptsite.cfg");
  719.  
  720.   /* Personal config. */
  721.   (void) read_config (passwd->pw_dir, ".enscriptrc");
  722.  
  723.   /*
  724.    * Options.
  725.    */
  726.  
  727.   /* Environment variables. */
  728.   handle_env_options ("ENSCRIPT");
  729.   handle_env_options ("GENSCRIPT");
  730.  
  731.   /* Command line arguments. */
  732.   handle_options (argc, argv);
  733.  
  734.   /* 
  735.    * Check options which have some validity conditions.
  736.    */
  737.  
  738.   /* Input encoding. */
  739.  
  740.   found = 0;
  741.   for (i = 0; !found && encodings[i].names[0]; i++)
  742.     for (j = 0; j < 3; j++)
  743.       if (encodings[i].names[j] != NULL && MATCH (encodings[i].names[j],
  744.                           encoding_name))
  745.     {
  746.       /* Found a match for this encoding. */
  747.       encoding = encodings[i].encoding;
  748.       encoding_name = encodings[i].names[0];
  749.       if (nl < 0)
  750.         nl = encodings[i].nl;
  751.       bs = encodings[i].bs;
  752.       found = 1;
  753.       break;
  754.     }
  755.   if (!found)
  756.     fatal (_("unknown encoding: %s"), encoding_name);
  757.  
  758.   /* Fonts. */
  759.  
  760.   /* Default font for landscape, 2 column printing is Courier 7. */
  761.   if (!user_body_font_defined && landscape && num_columns > 1)
  762.     Fpt = 7.0;
  763.  
  764.   /* Cache for font AFM information. */
  765.   afm_cache = strhash_init ();
  766.  
  767.   /* Open AFM library. */
  768.   afm_error = afm_create (afm_path, verbose, &afm);
  769.   if (afm_error != AFM_SUCCESS)
  770.     {
  771.       char buf[256];
  772.  
  773.       afm_error_to_string (afm_error, buf);
  774.       fatal (_("couldn't open AFM library: %s"), buf);
  775.     }
  776.  
  777.   /*
  778.    * Save default Fpt and Fname since special escape 'font' can change 
  779.    * it and later we might want to switch back to the "default" font.
  780.    */
  781.   default_Fpt = Fpt;
  782.   default_Fname = Fname;
  783.  
  784.   /* Register that document uses at least these fonts. */
  785.   strhash_put (res_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
  786.   strhash_put (res_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
  787.  
  788.   /* As a default, download both named fonts. */
  789.   strhash_put (download_fonts, Fname, strlen (Fname) + 1, NULL, NULL);
  790.   strhash_put (download_fonts, HFname, strlen (HFname) + 1, NULL, NULL);
  791.  
  792.   /* Read font's character widths and character types. */
  793.   read_font_info ();
  794.  
  795.   /* Count the line indentation. */
  796.   line_indent = parse_float (line_indent_spec, 1, 1);
  797.  
  798.   /* Escape page header string. */
  799.   if (page_header != NULL)
  800.     page_header = escape_string (page_header);
  801.  
  802.   /* List media names. */
  803.   if (list_media)
  804.     {
  805.       printf (_("known media:\n\
  806. name             width\theight\tllx\tlly\turx\tury\n\
  807. ------------------------------------------------------------\n"));
  808.       for (mentry = media_names; mentry; mentry = mentry->next)
  809.     printf ("%-16s %d\t%d\t%d\t%d\t%d\t%d\n",
  810.         mentry->name, mentry->w, mentry->h,
  811.         mentry->llx, mentry->lly, mentry->urx, mentry->ury);
  812.       /* Exit after listing. */
  813.       exit (0);
  814.     }
  815.  
  816.   /* Output media. */
  817.   for (mentry = media_names; mentry; mentry = mentry->next)
  818.     if (strcmp (media_name, mentry->name) == 0)
  819.       {
  820.     media = mentry;
  821.     break;
  822.       }
  823.   if (media == NULL)
  824.     fatal (_("do not know anything about media \"%s\""), media_name);
  825.  
  826.   /* Page label format. */
  827.   if (MATCH (page_label_format, "short"))
  828.     page_label = LABEL_SHORT;
  829.   else if (MATCH (page_label_format, "long"))
  830.     page_label = LABEL_LONG;
  831.   else
  832.     fatal (_("illegal page label format \"%s\""), page_label_format);
  833.  
  834.   /* Non-printable format. */
  835.   if (MATCH (npf_name, "space"))
  836.     non_printable_format = NPF_SPACE;
  837.   else if (MATCH (npf_name, "questionmark"))
  838.     non_printable_format = NPF_QUESTIONMARK;
  839.   else if (MATCH (npf_name, "caret"))
  840.     non_printable_format = NPF_CARET;
  841.   else if (MATCH (npf_name, "octal"))
  842.     non_printable_format = NPF_OCTAL;
  843.   else
  844.     fatal (_("illegal non-printable format \"%s\""), npf_name);
  845.  
  846.   /* 
  847.    * Count output media dimensions.
  848.    */
  849.  
  850.   if (landscape)
  851.     {
  852.       d_page_w = media->ury - media->lly;
  853.       d_page_h = media->urx - media->llx;
  854.     }
  855.   else
  856.     {
  857.       d_page_w = media->urx - media->llx;
  858.       d_page_h = media->ury - media->lly;
  859.     }
  860.  
  861.   /*
  862.    * Underlay (this must come after output media dimensions, because
  863.    * `underlay position' needs them).
  864.    */
  865.   if (underlay != NULL)
  866.     {
  867.       strhash_put (res_fonts, ul_font, strlen (ul_font) + 1, NULL, NULL);
  868.       underlay = escape_string (underlay);
  869.     }
  870.  
  871.   /* Underlay X-coordinate. */
  872.   ul_x = strtod (ul_position, &cp);
  873.   if (cp == ul_position)
  874.     {
  875.     malformed_position:
  876.       fatal (_("malformed underlay position: %s"), ul_position);
  877.     }
  878.   if (ul_position[0] == '-')
  879.     ul_x += d_page_w;
  880.  
  881.   /* Underlay Y-coordinate. */
  882.   ul_y = strtod (cp, &cp2);
  883.   if (cp2 == cp)
  884.     goto malformed_position;
  885.   if (cp[0] == '-')
  886.     ul_y += d_page_h;
  887.  
  888.   /* Underlay Angle. */
  889.   if (!ul_angle_p)
  890.     /* No angle given, count the default. */
  891.     ul_angle = (atan2 (-d_page_h, d_page_w) / 3.14159265 * 180);
  892.  
  893.   /* Underlay style. */
  894.   if (strcmp (ul_style_str, "outline") == 0)
  895.     ul_style = UL_STYLE_OUTLINE;
  896.   else if (strcmp (ul_style_str, "filled") == 0)
  897.     ul_style = UL_STYLE_FILLED;
  898.   else
  899.     fatal (_("illegal underlay style: %s"), ul_style_str);
  900.  
  901.   /*
  902.    * Header.  Note! The header attributes can be changed from
  903.    * the `.hdr' files, these are only the defaults.
  904.    */
  905.  
  906.   d_header_w = d_page_w;
  907.   switch (header)
  908.     {
  909.     case HDR_NONE:
  910.       d_header_h = 0;
  911.       break;
  912.  
  913.     case HDR_SIMPLE:
  914.       d_header_h = HFpt * 1.5;
  915.       break;
  916.  
  917.     case HDR_FANCY:
  918.       d_header_h = 36;
  919.       break;
  920.     }
  921.  
  922.   /* List options. */
  923.   if (list_options)
  924.     {
  925.       do_list_options ();
  926.       exit (1);
  927.     }
  928.  
  929.   /* Open output file. */
  930.   if (output_file == OUTPUT_FILE_NONE)
  931.     {
  932.       /* Format spooler options. */
  933.       spooler_options[0] = '\0';
  934.       if (mail)
  935.     strcat (spooler_options, "-m ");
  936.       if (no_job_header)
  937.     strcat (spooler_options, "-h ");
  938.       if (printer_options)
  939.     strcat (spooler_options, printer_options);
  940.  
  941.       /* Open printer. */
  942.       ofp = printer_open (spooler_command, spooler_options, queue_param,
  943.               printer, &printer_context);
  944.       if (ofp == NULL)
  945.     fatal (_("couldn't open printer `%s': %s"), printer, strerror (errno));
  946.     }
  947.   else if (output_file == OUTPUT_FILE_STDOUT)
  948.     ofp = stdout;
  949.   else
  950.     {
  951.       ofp = fopen (output_file, "w");
  952.       if (ofp == NULL)
  953.     fatal (_("couldn't create output file \"%s\": %s"), output_file,
  954.            strerror (errno));
  955.     }
  956.  
  957.  
  958.   /* 
  959.    * Process files.
  960.    */
  961.  
  962.   if (optind == argc)
  963.     {
  964.       /* stdin's modification time is the current time. */
  965.       memcpy (&mod_tm, &run_tm, sizeof (run_tm));
  966.  
  967.       if (is_open (&is, stdin, NULL, input_filter))
  968.     {
  969.       process_file (title_given ? title : "", &is);
  970.       is_close (&is);
  971.     }
  972.     }
  973.   else
  974.     {
  975.       for (; optind < argc; optind++)
  976.     {
  977.       if (is_open (&is, NULL, argv[optind], input_filter))
  978.         {
  979.           struct stat stat_st;
  980.  
  981.           /* Get modification time. */
  982.           if (stat (argv[optind], &stat_st) == 0)
  983.         {
  984.           tim = stat_st.st_mtime;
  985.           tm = localtime (&tim);
  986.           memcpy (&mod_tm, tm, sizeof (*tm));
  987.  
  988.           process_file (argv[optind], &is);
  989.         }
  990.           else
  991.         error (_("couldn't stat input file \"%s\": %s"), argv[optind],
  992.                strerror (errno));
  993.  
  994.           is_close (&is);
  995.         }
  996.     }
  997.     }
  998.  
  999.   /* Give trailer a chance to dump itself. */
  1000.   dump_ps_trailer ();
  1001.  
  1002.   /*
  1003.    * Append ^D to the end of the output?  Note! It must be ^D followed
  1004.    * by a newline.
  1005.    */
  1006.   if (append_ctrl_D)
  1007.     fprintf (ofp, "\004\n");
  1008.  
  1009.   /* Close output file. */
  1010.   if (output_file == OUTPUT_FILE_NONE)
  1011.     printer_close (printer_context);
  1012.   else if (output_file != OUTPUT_FILE_STDOUT)
  1013.     fclose (ofp);
  1014.  
  1015.   /* Tell how things went. */
  1016.   message (0, _("[ %d pages * %d copy ]"), total_pages, num_copies);
  1017.   if (output_file == OUTPUT_FILE_NONE)
  1018.     message (0, _(" sent to %s\n"), printer ? printer : _("printer"));
  1019.   else
  1020.     message (0, _(" left in %s\n"),
  1021.          output_file == OUTPUT_FILE_STDOUT ? "-" : output_file);
  1022.   if (num_truncated_lines)
  1023.     message (0, _("%d lines were %s\n"), num_truncated_lines,
  1024.          truncate_lines ? _("truncated") : _("wrapped"));
  1025.  
  1026.   if (num_missing_chars)
  1027.     {
  1028.       message (0, _("%d characters were missing\n"), num_missing_chars);
  1029.       if (list_missing_characters)
  1030.     {
  1031.       message (0, _("missing character codes (decimal):\n"));
  1032.       do_list_missing_characters (missing_chars);
  1033.     }
  1034.     }
  1035.  
  1036.   if (num_non_printable_chars)
  1037.     {
  1038.       message (0, _("%d non-printable characters\n"), num_non_printable_chars);
  1039.       if (list_missing_characters)
  1040.     {
  1041.       message (0, _("non-printable character codes (decimal):\n"));
  1042.       do_list_missing_characters (non_printable_chars);
  1043.     }
  1044.     }
  1045.  
  1046.   /* This is the end. */
  1047.   return 0;
  1048. }
  1049.  
  1050.  
  1051. /*
  1052.  * Static functions.
  1053.  */
  1054.  
  1055.  
  1056. static void
  1057. handle_env_options (char *var)
  1058. {
  1059.   int argc;
  1060.   char **argv;
  1061.   char *string;
  1062.   char *str;
  1063.   int i;
  1064.  
  1065.   string = getenv (var);
  1066.   if (string == NULL)
  1067.     return;
  1068.  
  1069.   message (1, "handle_env_options(): %s=\"%s\"\n", var, string);
  1070.  
  1071.   /* Copy string so we can modify it in place. */
  1072.   str = xstrdup (string);
  1073.  
  1074.   /*
  1075.    * We can count this, each option takes at least 1 character and one 
  1076.    * space.  We also need one for program's name and one for the 
  1077.    * trailing NULL. 
  1078.    */
  1079.   argc = (strlen (str) + 1) / 2 + 2;
  1080.   argv = xcalloc (argc, sizeof (char *));
  1081.   
  1082.   /* Set program name. */
  1083.   argc = 0;
  1084.   argv[argc++] = program;
  1085.  
  1086.   /* Split string and set arguments to argv array. */
  1087.   i = 0;
  1088.   while (str[i])
  1089.     {
  1090.       /* Skip leading whitespace. */
  1091.       for (; str[i] && isspace (str[i]); i++)
  1092.     ;
  1093.       if (!str[i])
  1094.     break;
  1095.  
  1096.       /* Check for quoted arguments. */
  1097.       if (str[i] == '"' || str[i] == '\'')
  1098.     {
  1099.       int endch = str[i++];
  1100.  
  1101.       argv[argc++] = str + i;
  1102.  
  1103.       /* Skip until we found the end of the quotation. */
  1104.       for (; str[i] && str[i] != endch; i++)
  1105.         ;
  1106.       if (!str[i])
  1107.         fatal (_("syntax error in option string %s=\"%s\":\n\
  1108. missing end of quotation: %c"), var, string, endch);
  1109.  
  1110.       str[i++] = '\0';
  1111.     }
  1112.       else
  1113.     {
  1114.       argv[argc++] = str + i;
  1115.  
  1116.       /* Skip until whitespace if found. */
  1117.       for (; str[i] && !isspace (str[i]); i++)
  1118.         ;
  1119.       if (str[i])
  1120.         str[i++] = '\0';
  1121.     }
  1122.     }
  1123.   
  1124.   /* argv[argc] must be NULL. */
  1125.   argv[argc] = NULL;
  1126.  
  1127.   message (2, "found following options (argc=%d):\n", argc);
  1128.   for (i = 0; i < argc; i++)
  1129.     message (2, "%3d = \"%s\"\n", i, argv[i]);
  1130.  
  1131.   /* Process options. */
  1132.   handle_options (argc, argv);
  1133.  
  1134.   /* Check that all got processed. */
  1135.   if (optind != argc)
  1136.     {
  1137.       message (0,
  1138.            _("warning: didn't process following options from \
  1139. environment variable %s:\n"),
  1140.            var);
  1141.       for (; optind < argc; optind++)
  1142.     message (0, _("  option %d = \"%s\"\n"), optind, argv[optind]);
  1143.     }
  1144.  
  1145.   /* Cleanup. */
  1146.   xfree (argv);
  1147.  
  1148.   /*
  1149.    * <str> must not be freed, since some global variables can point to
  1150.    * its elements
  1151.    */
  1152. }
  1153.  
  1154.  
  1155. static void
  1156. handle_options (int argc, char *argv[])
  1157. {
  1158.   int c;
  1159.   PageRange *prange;
  1160.  
  1161.   /* Reset optind. */
  1162.   optind = 0;
  1163.  
  1164.   while (1)
  1165.     {
  1166.       int option_index = 0;
  1167.       const char *cp;
  1168.  
  1169.       c = getopt_long (argc, argv,
  1170.                "12a:b:BcCd:D:e::f:F:gGhH::i:I:jkKlL:mM:n:N:o:Op:P:qrRs:S:t:T:u::vVX:zZ",
  1171.                long_options, &option_index);
  1172.       
  1173.       if (c == EOF)
  1174.     break;
  1175.  
  1176.       switch (c)
  1177.     {
  1178.     case 0:            /* Long option found. */
  1179.       cp = long_options[option_index].name;
  1180.  
  1181.       if (strcmp (cp, "columns") == 0)
  1182.         num_columns = atoi (optarg);
  1183.       break;
  1184.  
  1185.       /* Short options. */
  1186.  
  1187.     case '1':        /* one column */
  1188.     case '2':        /* two columns */
  1189.       num_columns = c - '0';
  1190.       break;
  1191.  
  1192.     case 'a':        /* pages */
  1193.       prange = (PageRange *) xcalloc (1, sizeof (PageRange));
  1194.  
  1195.       if (strcmp (optarg, "odd") == 0)
  1196.         prange->odd = 1;
  1197.       else if (strcmp (optarg, "even") == 0)
  1198.         prange->even = 1;
  1199.       else
  1200.         {
  1201.           cp = strchr (optarg, '-');
  1202.           if (cp)
  1203.         {
  1204.           if (optarg[0] == '-')
  1205.             /* -end */
  1206.             prange->end = atoi (optarg + 1);
  1207.           else if (cp[1] == '\0')
  1208.             {
  1209.               /* start- */
  1210.               prange->start = atoi (optarg);
  1211.               prange->end = (unsigned int) -1;
  1212.             }
  1213.           else
  1214.             {
  1215.               /* start-end */
  1216.               prange->start = atoi (optarg);
  1217.               prange->end = atoi (cp + 1);
  1218.             }
  1219.         }
  1220.           else
  1221.         /* pagenumber */
  1222.         prange->start = prange->end = atoi (optarg);
  1223.         }
  1224.  
  1225.       prange->next = page_ranges;
  1226.       page_ranges = prange;
  1227.       break;
  1228.  
  1229.     case 'b':        /* page header */
  1230.       page_header = optarg;
  1231.       break;
  1232.  
  1233.     case 'B':        /* no page headers */
  1234.       header = HDR_NONE;
  1235.       break;
  1236.  
  1237.     case 'c':        /* truncate (cut) long lines */
  1238.       truncate_lines = 1;
  1239.       break;
  1240.  
  1241.     case 'C':        /* line numbers */
  1242.       line_numbers = 1;
  1243.       break;
  1244.  
  1245.     case 'd':        /* specify printer */
  1246.     case 'P':
  1247.       printer = optarg;
  1248.       output_file = OUTPUT_FILE_NONE;
  1249.       break;
  1250.  
  1251.     case 'D':        /* setpagedevice */
  1252.       parse_key_value_pair (pagedevice, optarg);
  1253.       break;
  1254.  
  1255.     case 'e':        /* special escapes */
  1256.       special_escapes = 1;
  1257.       if (optarg)
  1258.         /* Specify the escape character. */
  1259.         escape_char = atoi (optarg);
  1260.       break;
  1261.  
  1262.     case 'f':        /* font */
  1263.       if (!parse_font_spec (optarg, &Fname, &Fpt))
  1264.         fatal (_("malformed font spec: %s"), optarg);
  1265.       user_body_font_defined = 1;
  1266.       break;
  1267.  
  1268.     case 'F':        /* header font */
  1269.       if (!parse_font_spec (optarg, &HFname, &HFpt))
  1270.         fatal (_("malformed font spec: %s"), optarg);
  1271.       break;
  1272.  
  1273.     case 'g':        /* print anyway */
  1274.       /* nothing. */
  1275.       break;
  1276.  
  1277.     case 'G':        /* fancy header */
  1278.       header = HDR_FANCY;
  1279.       if (optarg)
  1280.         fancy_header_name = optarg;
  1281.       else
  1282.         fancy_header_name = fancy_header_default;
  1283.  
  1284.       if (!file_existsp (fancy_header_name, ".hdr"))
  1285.         fatal (_("couldn't find header definition file \"%s.hdr\""),
  1286.            fancy_header_name);
  1287.       break;
  1288.  
  1289.     case 'h':        /* no job header */
  1290.       no_job_header = 1;
  1291.       break;
  1292.  
  1293.     case 'H':        /* highlight bars */
  1294.       if (optarg)
  1295.         highlight_bars = atoi (optarg);
  1296.       else
  1297.         highlight_bars = 2;
  1298.       break;
  1299.       
  1300.     case 'i':        /* line indent */
  1301.       line_indent_spec = optarg;
  1302.       break;
  1303.  
  1304.     case 'I':        /* input filter */
  1305.       input_filter = optarg;
  1306.       break;
  1307.  
  1308.     case 'j':        /* borders */
  1309.       borders = 1;
  1310.       break;
  1311.  
  1312.     case 'k':        /* enable page prefeed */
  1313.       page_prefeed = 1;
  1314.       break;
  1315.  
  1316.     case 'K':        /* disable page prefeed */
  1317.       page_prefeed = 0;
  1318.       break;
  1319.  
  1320.     case 'l':        /* simulate lineprinter */
  1321.       lines_per_page = 66;
  1322.       header = HDR_NONE;
  1323.       landscape = 0;
  1324.       num_columns = 1;
  1325.       break;
  1326.  
  1327.     case 'L':        /* lines per page */
  1328.       lines_per_page = atoi (optarg);
  1329.       if (lines_per_page <= 0)
  1330.         fatal (_("must print at least one line per each page: %s"),
  1331.            argv[optind]);
  1332.       break;
  1333.  
  1334.     case 'm':        /* send mail upon completion */
  1335.       mail = 1;
  1336.       break;
  1337.  
  1338.     case 'M':        /* select output media */
  1339.       media_name = optarg;
  1340.       break;
  1341.  
  1342.     case 'n':        /* num copies */
  1343.       num_copies = atoi (optarg);
  1344.       break;
  1345.  
  1346.     case 'N':        /* newline character */
  1347.       if (!(optarg[0] == 'n' || optarg[0] == 'r') || optarg[1] != '\0')
  1348.         {
  1349.           fprintf (stderr, _("%s: illegal newline character specifier: \
  1350. '%s': expected 'n' or 'r'\n"),
  1351.                program, optarg);
  1352.           goto option_error;
  1353.         }
  1354.       if (optarg[0] == 'n')
  1355.         nl = '\n';
  1356.       else
  1357.         nl = '\r';
  1358.       break;
  1359.  
  1360.     case 'o':
  1361.     case 'p':        /* output file */
  1362.       /* Check output file "-". */
  1363.       if (strcmp (optarg, "-") == 0)
  1364.         output_file = OUTPUT_FILE_STDOUT;
  1365.       else
  1366.         output_file = optarg;
  1367.       break;
  1368.  
  1369.     case 'O':        /* list missing characters */
  1370.       list_missing_characters = 1;
  1371.       break;
  1372.  
  1373.     case 'q':        /* quiet */
  1374.       quiet = 1;
  1375.       verbose = 0;
  1376.       break;
  1377.  
  1378.     case 'r':        /* landscape */
  1379.       landscape = 1;
  1380.       break;
  1381.  
  1382.     case 'R':        /* portrait */
  1383.       landscape = 0;
  1384.       break;
  1385.  
  1386.     case 's':        /* baselineskip */
  1387.       baselineskip = atof (optarg);
  1388.       break;
  1389.  
  1390.     case 'S':        /* statusdict */
  1391.       parse_key_value_pair (statusdict, optarg);
  1392.       break;
  1393.  
  1394.     case 't':
  1395.       title = optarg;
  1396.       title_given = 1;
  1397.       break;
  1398.  
  1399.     case 'T':        /* tabulator size */
  1400.       tabsize = atoi (optarg);
  1401.       if (tabsize <= 0)
  1402.         tabsize = 1;
  1403.       break;
  1404.  
  1405.     case 'u':        /* underlay */
  1406.       underlay = optarg;
  1407.       break;
  1408.  
  1409.     case 'v':        /* verbose */
  1410.       if (optarg)
  1411.         verbose = atoi (optarg);
  1412.       else
  1413.         verbose++;
  1414.       quiet = 0;
  1415.       break;
  1416.  
  1417.     case 'V':        /* version */
  1418.       version ();
  1419.       exit (0);
  1420.       break;
  1421.  
  1422.     case 'X':        /* input encoding */
  1423.       encoding_name = optarg;
  1424.       break;
  1425.  
  1426.     case 'z':        /* no form feeds */
  1427.       interpret_formfeed = 0;
  1428.       break;
  1429.  
  1430.     case 'Z':        /* pass through */
  1431.       pass_through = 1;
  1432.       break;
  1433.  
  1434.     case 128:        /* underlay font */
  1435.       if (!parse_font_spec (optarg, &ul_font, &ul_ptsize))
  1436.         fatal (_("malformed font spec: %s"), optarg);
  1437.       break;
  1438.  
  1439.     case 129:        /* underlay gray */
  1440.       ul_gray = atof (optarg);
  1441.       break;
  1442.  
  1443.     case 130:        /* page label format */
  1444.       page_label_format = optarg;
  1445.       break;
  1446.  
  1447.     case 131:        /* download font */
  1448.       strhash_put (download_fonts, optarg, strlen (optarg) + 1, NULL,
  1449.                NULL);
  1450.       break;
  1451.  
  1452.     case 132:        /* underlay angle */
  1453.       ul_angle = atof (optarg);
  1454.       ul_angle_p = 1;
  1455.       break;
  1456.  
  1457.     case 133:        /* underlay position */
  1458.       ul_position = optarg;
  1459.       ul_position_p = 1;
  1460.       break;
  1461.  
  1462.     case 134:        /* non-printable format */
  1463.       npf_name = optarg;
  1464.       break;
  1465.  
  1466.     case 135:        /* help */
  1467.       usage ();
  1468.       exit (0);
  1469.       break;
  1470.  
  1471.     case 136:        /* highlight bar gray */
  1472.       highlight_bar_gray = atof (optarg);
  1473.       break;
  1474.  
  1475.     case 137:        /* underlay style */
  1476.       ul_style_str = optarg;
  1477.       break;
  1478.  
  1479.     case 138:        /* filter stdin */
  1480.       input_filter_stdin = optarg;
  1481.       break;
  1482.  
  1483.     case 139:        /* extra options for the printer spooler */
  1484.       printer_options = optarg;
  1485.       break;
  1486.  
  1487.     case '?':        /* Errors found during getopt_long(). */
  1488.     option_error:
  1489.       fprintf (stderr, _("Try `%s --help' for more information.\n"),
  1490.            program);
  1491.       exit (1);
  1492.       break;
  1493.       
  1494.     default:
  1495.       printf ("Hey!  main() didn't handle option \"%c\" (%d)", c, c);
  1496.       if (optarg)
  1497.         printf (" with arg %s", optarg);
  1498.       printf ("\n");
  1499.       fatal ("This is a bug!");
  1500.       break;
  1501.     }
  1502.     }
  1503. }
  1504.  
  1505.  
  1506. #define TF(val) ((val) ? 't' : 'f')
  1507.  
  1508. static void
  1509. do_list_options ()
  1510. {
  1511.   int i, j;
  1512.   char *cp, *cp2;
  1513.  
  1514.   printf ("libpath=\"%s\"\n",     libpath);
  1515.   printf ("printer=\"%s\"\n",     printer ? printer : "");
  1516.   printf ("queue_param=\"%s\"\n",     queue_param);
  1517.   printf ("verbose=%d\n",         verbose);
  1518.   printf ("num_copies=%d\n",     num_copies);
  1519.   printf ("title=\"%s\"\n",     title ? title : "");
  1520.   printf ("columns=%d\n",         num_columns);
  1521.   printf ("truncate=#%c\n",     TF (truncate_lines));
  1522.   printf ("line_numbers=#%c\n",     TF (line_numbers));
  1523.   printf ("mail=#%c\n",         TF (mail));
  1524.   printf ("quiet=#%c\n",         TF (quiet));
  1525.   printf ("landscape=#%c\n",     TF (landscape));
  1526.   
  1527.   printf ("header=");
  1528.   switch (header)
  1529.     {
  1530.     case HDR_NONE:
  1531.       printf ("none");
  1532.       break;
  1533.  
  1534.     case HDR_SIMPLE:
  1535.       printf ("simple");
  1536.       break;
  1537.  
  1538.     case HDR_FANCY:
  1539.       printf ("fancy (%s)", fancy_header_name);
  1540.       break;
  1541.     }
  1542.   printf ("\n");
  1543.   
  1544.   printf ("page_header=\"%s\"\n", page_header ? page_header : "");
  1545.   printf ("font: name=%s size=%gpt\n", Fname, Fpt);
  1546.   printf ("header font: name=%s size=%gpt\n", HFname, HFpt);
  1547.   printf ("output_file=%s\n",
  1548.       (output_file == OUTPUT_FILE_NONE
  1549.        ? "none"
  1550.        : (output_file == OUTPUT_FILE_STDOUT
  1551.           ? "stdout"
  1552.           : output_file)));
  1553.   printf ("media=%s (w=%d, h=%d, llx=%d, lly=%d, urx=%d, ury=%d)\n",
  1554.       media->name, media->w, media->h, media->llx, media->lly,
  1555.       media->urx,media->ury);
  1556.   
  1557.   printf ("encoding=%s\n",         encoding_name);
  1558.   printf ("interpret_formfeed=#%c\n",    TF (interpret_formfeed));
  1559.   printf ("pass_through=#%c\n",        TF (pass_through));
  1560.   printf ("spooler_command=\"%s\"\n",     spooler_command);
  1561.   printf ("special_escapes=#%c\n",     TF (special_escapes));
  1562.   printf ("tabsize=%d\n",         tabsize);
  1563.   printf ("baselineskip=%g\n",     baselineskip);
  1564.   
  1565.   /* statusdict key-value pairs */
  1566.   printf ("statusdict: ");
  1567.   for (i = strhash_get_first (statusdict, &cp, &j, (void **) &cp2); i;
  1568.        i = strhash_get_next (statusdict, &cp, &j, (void **) &cp2))
  1569.     printf ("%s %s ", cp2, cp);
  1570.   printf ("\n");
  1571.   
  1572.   /* setpagedevice key-value pairs */
  1573.   printf ("setpagedevice: << ");
  1574.   for (i = strhash_get_first (pagedevice, &cp, &j, (void **) &cp2); i;
  1575.        i = strhash_get_next (pagedevice, &cp, &j, (void **) &cp2))
  1576.     printf ("/%s %s ", cp, cp2);
  1577.   printf (">>\n");
  1578.   
  1579.   printf ("nl=%c\n",         nl == '\n' ? 'n' : 'r');
  1580.   printf ("AFM path=%s\n",         afm_path ? afm_path : "(default)");
  1581.   
  1582.   /* Underlay. */
  1583.   printf ("underlay=(%s)\n",     underlay ? underlay : "");
  1584.   printf ("ul_gray=%g\n",         ul_gray);
  1585.   printf ("ul_font=%s %gpt\n",     ul_font, ul_ptsize);
  1586.   printf ("ul_position=%s (%g, %g)\n",    ul_position, ul_x, ul_y);
  1587.   printf ("ul_angle=%g\n",        ul_angle);
  1588.   
  1589.   /* Download fonts. */
  1590.   printf ("download-fonts:");
  1591.   for (i = strhash_get_first (download_fonts, &cp, &j, (void **) &cp2); i;
  1592.        i = strhash_get_next (download_fonts, &cp, &j, (void **) &cp2))
  1593.     printf (" %s", cp);
  1594.   printf ("\n");
  1595. }
  1596.  
  1597.  
  1598. static void
  1599. usage ()
  1600. {
  1601.   printf (_("\
  1602. Usage: %s [OPTION]... [FILE]...\n\
  1603. Mandatory arguments to long options are mandatory for short options too.\n\
  1604.   -1                         same as --columns=1\n\
  1605.   -2                         same as --columns=2\n\
  1606.       --columns=NUM          specify the number of columns per page\n\
  1607.   -a, --pages=PAGES          specify which pages are printed\n\
  1608.   -b, --header=HEADER        set page header\n\
  1609.   -B, --no-header            no page headers\n\
  1610.   -c, --truncate-lines       cut long lines (default is to wrap)\n\
  1611.   -C, --line-numbers         precede each line with its line number\n\
  1612.   -d                         an alias for option --printer\n\
  1613.   -D, --setpagedevice=KEY[:VALUE]\n\
  1614.                              pass a page device definition to output\n\
  1615.   -e, --escapes[=CHAR]       enable special escape interpretation\n"),
  1616.           program);
  1617.  
  1618.   printf (_("\
  1619.   -f, --font=NAME            use font NAME for body text\n\
  1620.   -F, --header-font=NAME     use font NAME for header texts\n\
  1621.   -g, --print-anyway         nothing (compatibility option)\n\
  1622.   -G                         same as --fancy-header\n\
  1623.       --fancy-header[=NAME]  select fancy page header\n\
  1624.   -h, --no-job-header        suppress the job header page\n\
  1625.   -H, --highlight-bars=NUM   specify how high highlight bars are\n\
  1626.   -i, --indent=NUM           set line indent to NUM characters\n\
  1627.   -I, --filter=CMD           read input files through input filter CMD\n\
  1628.   -j, --borders              print borders around columns\n\
  1629.   -k, --page-prefeed         enable page prefeed\n\
  1630.   -K, --no-page-prefeed      disable page prefeed\n\
  1631.   -l, --lineprinter          simulate lineprinter, this is an alias for:\n\
  1632.                                --lines-per-page=66, --no-header, --portrait,\n\
  1633.                                --columns=1\n"));
  1634.  
  1635.   printf (_("\
  1636.   -L, --lines-per-page=NUM   specify how many lines are printed on each page\n\
  1637.   -m, --mail                 send mail upon completion\n\
  1638.   -M, --media=NAME           use output media NAME\n\
  1639.   -n, --copies=NUM           print NUM copies of each page\n\
  1640.   -N, --newline=NL           select the newline character.  Possible\n\
  1641.                              values for NL are: n (`\\n') and r (`\\r').\n\
  1642.   -o                         an alias for option --output\n\
  1643.   -O, --missing-characters   list missing characters\n\
  1644.   -p, --output=FILE          leave output to file FILE.  If FILE is `-',\n\
  1645.                              leave output to stdout.\n\
  1646.   -P, --printer=NAME         print output to printer NAME\n\
  1647.   -q, --quiet, --silent      be really quiet\n\
  1648.   -r, --landscape            print in landscape mode\n\
  1649.   -R, --portrait             print in portrait mode\n"));
  1650.  
  1651.   printf (_("\
  1652.   -s, --baselineskip=NUM     set baselineskip to NUM\n\
  1653.   -S, --statusdict=KEY[:VALUE]\n\
  1654.                              pass a statusdict definition to the output\n\
  1655.   -t, --title=TITLE          set banner page's job title to TITLE.  Option\n\
  1656.                              sets also the name of the input file stdin.\n\
  1657.   -T, --tabsize=NUM          set tabulator size to NUM\n\
  1658.   -u, --underlay[=TEXT]      print TEXT under every page\n\
  1659.   -v, --verbose              tell what we are doing\n\
  1660.   -V, --version              print version number\n\
  1661.   -X, --encoding=NAME        use input encoding NAME\n\
  1662.   -z, --no-formfeed          do not interpret form feed characters\n\
  1663.   -Z, --pass-through         pass through PostScript and PCL files\n\
  1664.                              without any modifications\n"));
  1665.  
  1666.   printf (_("Long-only options:\n\
  1667.   --download-font=NAME       download font NAME\n\
  1668.   --filter-stdin=NAME        specify how stdin is shown to the input filter\n\
  1669.   --help                     print this help and exit\n\
  1670.   --highlight-bar-gray=NUM   print highlight bars with gray NUM (0 - 1)\n\
  1671.   --list-media               list names of all known media\n\
  1672.   --list-options             list all options and their values\n\
  1673.   --non-printable-format=FMT specify how non-printable chars are printed\n\
  1674.   --page-label-format=FMT    set page label format to FMT\n\
  1675.   --printer-options=OPTIONS  pass extra options to the printer command\n\
  1676.   --ul-angle=ANGLE           set underlay text's angle to ANGLE\n\
  1677.   --ul-font=NAME             print underlays with font NAME\n\
  1678.   --ul-gray=NUM              print underlays with gray value NUM\n\
  1679.   --ul-position=POS          set underlay's starting position to POS\n\
  1680.   --ul-style=STYLE           print underlays with style STYLE\n\
  1681. "));
  1682. }
  1683.  
  1684.  
  1685. static void
  1686. version ()
  1687. {
  1688.   printf ("%s\n", version_string);
  1689. }
  1690.